
/*************************************************
 * HISTORY:                                      *
 *	06/22/2020 pyx : Created.                    *
 *	03/04/2021 pyx : Edited.                     *
=================================================*/

#include "DATransformerConnector.h"

Connector::Connector()
{
    try
    {
        driver = get_driver_instance();
        con = driver->connect(DBHOST, USER, PASSWORD);
        con->setAutoCommit(0);
        std::cout << "Connected!DataBase connection autocommit mode = " << con->getAutoCommit() << std::endl;

        con->setSchema("dadb");
        std::cout << "ok set" << std::endl;
        check_symbol_prep_stmt = con->prepareStatement("SELECT * FROM symboltable WHERE signature = ?");
        insert_symbol_prep_stmt = con->prepareStatement("INSERT INTO symboltable (sid,signature,symboltype,name) VALUES (?,?,?,?)");

        check_def_prep_stmt = con->prepareStatement("SELECT * FROM globaldeftable WHERE sid = ? AND fid = ? AND location = ?");
        insert_def_prep_stmt = con->prepareStatement("INSERT INTO globaldeftable (refid,sid,fid,reftype,location) VALUES (?,?,?,?,?)");

        check_dec_prep_stmt = con->prepareStatement("SELECT * FROM globaldectable WHERE sid = ? AND fid = ? AND location = ?");
        insert_dec_prep_stmt = con->prepareStatement("INSERT INTO globaldectable (refid,sid,fid,reftype,location) VALUES (?,?,?,?,?)");

        check_ref_prep_stmt = con->prepareStatement("SELECT * FROM reftable WHERE sid = ? AND fid = ? AND location = ?");
        insert_ref_prep_stmt = con->prepareStatement("INSERT INTO reftable (refid,sid,fid,reftype,location) VALUES (?,?,?,?,?)");

        check_file_prep_stmt = con->prepareStatement("SELECT * FROM filetable WHERE filepath = ? ");
        insert_file_prep_stmt = con->prepareStatement("INSERT INTO filetable (filepath,fid) VALUES (?,?)");

        check_dup_sym_dep_prep_stmt = con->prepareStatement("SELECT * FROM symboldeptable WHERE ssid = ? and esid = ? and sdeptype=?");
        insert_sym_dep_prep_stmt = con->prepareStatement("INSERT INTO symboldeptable (sdepid,ssid,esid,sdeptype) VALUES (?,?,?,?)");
    }
    catch (sql::SQLException &e)
    {
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        exit(1);
    }
    catch (std::runtime_error &e)
    {
        std::cout << "ERROR: " << e.what() << std::endl;

        exit(1);
    }
}

Connector::~Connector()
{
    try
    {
        con->commit();

        std::cout << "Cleaning up the resources .." << std::endl;

        /* Clean up */
        // delete res;
        // delete stmt;
        // delete prep_stmt;
        con->close();
        // delete con;
        std::cout << "out ~connector()" << std::endl;
    }
    catch (sql::SQLException &e)
    {
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        exit(1);
    }
    catch (std::runtime_error &e)
    {
        std::cout << "ERROR: " << e.what() << std::endl;

        exit(1);
    }
}

void Connector::commit()
{
    try
    {
        std::cout << "\tCommitting outstanding updates to the database .." << std::endl;
        con->commit();
    }
    catch (sql::SQLException &e)
    {
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        if (e.getErrorCode() == 1047)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "/nYour server does not seem to support Prepared Statements at all. ";
            std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
        }

        exit(1);
    }
    catch (std::runtime_error &e)
    {
        std::cout << "ERROR: " << e.what() << std::endl;

        exit(1);
    }
}

void Connector::insertSymbol(unsigned sid, std::string signature, int symboltype, std::string name)
{
    int updatecount;

    // if dup,error

    check_symbol_prep_stmt->setString(1, signature);
    sql::ResultSet *res = check_symbol_prep_stmt->executeQuery();
    int num = res->rowsCount();
    delete res;

    if (num != 0)
    {
        if ((SymbolType)symboltype == ST_Max)
            return;
        else
        {
            std::cout << "INTERNAL ERROR: inserting symboltable\n";
            std::cout << "same signature duplicated!" << signature << std::endl;
            exit(1);
        }
    }

    std::cout << "no dup\n";

    try
    {

        /* insert couple of rows of data into table using Prepared Statements */

        std::cout << "Inserting \"" << signature << "\"," << symboltype << "@" << sid << " into the symboltable!" << std::endl;
        insert_symbol_prep_stmt->setInt(1, sid);
        insert_symbol_prep_stmt->setString(2, signature);
        insert_symbol_prep_stmt->setInt(3, symboltype);
        insert_symbol_prep_stmt->setString(4, name);
        updatecount = insert_symbol_prep_stmt->executeUpdate();

        // insert_symbol_prep_stmt->close();
        std::cout << "Success,update " << updatecount << " row(s)" << std::endl;
    }
    catch (sql::SQLException &e)
    {
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        if (e.getErrorCode() == 1047)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "/nYour server does not seem to support Prepared Statements at all. ";
            std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
            exit(1);
        }
        else if (e.getErrorCode() == 1062)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "ignore it!" << std::endl;
        }

        else
            exit(1);
    }
    catch (std::runtime_error &e)
    {
        std::cout << "ERROR: " << e.what() << std::endl;

        exit(1);
    }

    return;
}

void Connector::insertDef(unsigned refid, unsigned sid, unsigned fid, int reftype, std::string location)
{
    int updatecount;

    // if dup, skip

    check_def_prep_stmt->setInt(1, sid);
    check_def_prep_stmt->setInt(2, fid);
    check_def_prep_stmt->setString(3, location);
    sql::ResultSet *res = check_def_prep_stmt->executeQuery();
    int num = res->rowsCount();
    delete res;

    if (num != 0)
    {
        return;
    }

    std::cout << "no dup\n";

    try
    {

        /* insert couple of rows of data into table using Prepared Statements */

        std::cout << "Inserting sid:" << sid << "@" << fid << " into the globaldeftable!" << std::endl;
        insert_def_prep_stmt->setInt(1, refid);
        insert_def_prep_stmt->setInt(2, sid);
        insert_def_prep_stmt->setInt(3, fid);
        insert_def_prep_stmt->setInt(4, reftype);
        insert_def_prep_stmt->setString(5, location);
        updatecount = insert_def_prep_stmt->executeUpdate();
        // insert_def_prep_stmt->close();
        std::cout << "Success,update " << updatecount << " row(s)" << std::endl;
    }
    catch (sql::SQLException &e)
    {
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        if (e.getErrorCode() == 1047)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "/nYour server does not seem to support Prepared Statements at all. ";
            std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
            exit(1);
        }
        else if (e.getErrorCode() == 1062)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "ignore it!" << std::endl;
        }

        else
            exit(1);
    }
    catch (std::runtime_error &e)
    {
        std::cout << "ERROR: " << e.what() << std::endl;

        exit(1);
    }

    return;
}

void Connector::insertDec(unsigned refid, unsigned sid, unsigned fid, int reftype, std::string location)
{
    int updatecount;

    // if dup, skip

    check_dec_prep_stmt->setInt(1, sid);
    check_dec_prep_stmt->setInt(2, fid);
    check_dec_prep_stmt->setString(3, location);
    sql::ResultSet *res = check_dec_prep_stmt->executeQuery();
    int num = res->rowsCount();
    delete res;

    if (num != 0)
    {
        return;
    }

    std::cout << "no dup\n";

    try
    {

        /* insert couple of rows of data into table using Prepared Statements */

        std::cout << "Inserting sid:" << sid << "@" << fid << " into the globaldectable!" << std::endl;
        insert_dec_prep_stmt->setInt(1, refid);
        insert_dec_prep_stmt->setInt(2, sid);
        insert_dec_prep_stmt->setInt(3, fid);
        insert_dec_prep_stmt->setInt(4, reftype);
        insert_dec_prep_stmt->setString(5, location);
        updatecount = insert_dec_prep_stmt->executeUpdate();
        // insert_dec_prep_stmt->close();
        std::cout << "Success,update " << updatecount << " row(s)" << std::endl;
    }
    catch (sql::SQLException &e)
    {
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        if (e.getErrorCode() == 1047)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "/nYour server does not seem to support Prepared Statements at all. ";
            std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
            exit(1);
        }
        else if (e.getErrorCode() == 1062)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "ignore it!" << std::endl;
        }

        else
            exit(1);
    }
    catch (std::runtime_error &e)
    {
        std::cout << "ERROR: " << e.what() << std::endl;

        exit(1);
    }

    return;
}

void Connector::insertRef(unsigned refid, unsigned sid, unsigned fid, int reftype, std::string location)
{
    int updatecount;

    // if dup, skip

    check_ref_prep_stmt->setInt(1, sid);
    check_ref_prep_stmt->setInt(2, fid);
    check_ref_prep_stmt->setString(3, location);
    sql::ResultSet *res = check_ref_prep_stmt->executeQuery();
    int num = res->rowsCount();
    delete res;

    if (num != 0)
    {
        return;
    }

    std::cout << "no dup\n";

    try
    {

        /* insert couple of rows of data into table using Prepared Statements */

        std::cout << "Inserting sid:" << sid << "@" << fid << " into the reftable!" << std::endl;
        insert_ref_prep_stmt->setInt(1, refid);
        insert_ref_prep_stmt->setInt(2, sid);
        insert_ref_prep_stmt->setInt(3, fid);
        insert_ref_prep_stmt->setInt(4, reftype);
        insert_ref_prep_stmt->setString(5, location);
        updatecount = insert_ref_prep_stmt->executeUpdate();
        // insert_ref_prep_stmt->close();
        std::cout << "Success,update " << updatecount << " row(s)" << std::endl;
    }
    catch (sql::SQLException &e)
    {
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        if (e.getErrorCode() == 1047)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "/nYour server does not seem to support Prepared Statements at all. ";
            std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
            exit(1);
        }
        else if (e.getErrorCode() == 1062)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "ignore it!" << std::endl;
        }

        else
            exit(1);
    }
    catch (std::runtime_error &e)
    {
        std::cout << "ERROR: " << e.what() << std::endl;

        exit(1);
    }

    return;
}

void Connector::insertSymbolDep(unsigned sdepid, unsigned ssid, unsigned esid, int symboldeptype)
{
    int updatecount;

    std::cout << "Inserting symbol dep:" << sdepid << "," << ssid << "," << esid << "," << symboldeptype << std::endl;

    try
    {

        check_dup_sym_dep_prep_stmt->setInt(1, ssid);
        check_dup_sym_dep_prep_stmt->setInt(2, esid);
        check_dup_sym_dep_prep_stmt->setInt(3, symboldeptype);

        sql::ResultSet *res = check_dup_sym_dep_prep_stmt->executeQuery();
        int num = res->rowsCount();
        delete res;

        if (num != 0)
        {
            return;
        }

        std::cout << "no dup\n";

        /* insert couple of rows of data into table using Prepared Statements */

        std::cout << "Inserting sdep:" << ssid << "-->" << esid << " into the symboldeptable!" << std::endl;
        insert_sym_dep_prep_stmt->setInt(1, sdepid);
        insert_sym_dep_prep_stmt->setInt(2, ssid);
        insert_sym_dep_prep_stmt->setInt(3, esid);
        insert_sym_dep_prep_stmt->setInt(4, symboldeptype);
        updatecount = insert_sym_dep_prep_stmt->executeUpdate();
        // insert_ref_prep_stmt->close();
        std::cout << "Success,update " << updatecount << " row(s)" << std::endl;
    }
    catch (sql::SQLException &e)
    {
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        if (e.getErrorCode() == 1047)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "/nYour server does not seem to support Prepared Statements at all. ";
            std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
            exit(1);
        }
        else if (e.getErrorCode() == 1062)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "ignore it!" << std::endl;
        }

        else
            exit(1);
    }
    catch (std::runtime_error &e)
    {
        std::cout << "ERROR: " << e.what() << std::endl;

        exit(1);
    }

    return;
}

void Connector::insertFile(std::string filepath, unsigned fid)
{

    int updatecount;

    // if dup,error

    check_file_prep_stmt->setString(1, filepath);
    sql::ResultSet *res = check_file_prep_stmt->executeQuery();
    int num = res->rowsCount();
    delete res;

    if (num != 0)
    {

        std::cout << "INTERNAL ERROR: inserting filetable\n";
        std::cout << "same filepath duplicated!" << filepath << std::endl;
        exit(1);
    }

    try
    {

        /* insert couple of rows of data into City table using Prepared Statements */

        std::cout << "Inserting \"" << filepath << "\"," << fid << " into the table: filetable!" << std::endl;
        insert_file_prep_stmt->setString(1, filepath);
        insert_file_prep_stmt->setInt(2, fid);
        updatecount = insert_file_prep_stmt->executeUpdate();
        // insert_file_prep_stmt->close();
        std::cout << "Success,update " << updatecount << " row(s)" << std::endl;
    }
    catch (sql::SQLException &e)
    {
        std::cout << "ERROR: " << e.what();
        std::cout << " (MySQL error code: " << e.getErrorCode();
        std::cout << ", SQLState: " << e.getSQLState() << ")" << std::endl;

        if (e.getErrorCode() == 1047)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "/nYour server does not seem to support Prepared Statements at all. ";
            std::cout << "Perhaps MYSQL < 4.1?" << std::endl;
            exit(1);
        }
        else if (e.getErrorCode() == 1062)
        {
            /*
            Error: 1047 SQLSTATE: 08S01 (ER_UNKNOWN_COM_ERROR)
            Message: Unknown command
            */
            std::cout << "ignore it!" << std::endl;
        }

        else
            exit(1);
    }
    catch (std::runtime_error &e)
    {
        std::cout << "ERROR: " << e.what() << std::endl;

        exit(1);
    }

    return;
}